package cn.edu.scau.cmi.ema.service;

import cn.edu.scau.cmi.ema.base.CmiPagination;
import cn.edu.scau.cmi.ema.domain.Address;
import cn.edu.scau.cmi.ema.domain.Detect;
import cn.edu.scau.cmi.ema.domain.Detectdepartment;
import cn.edu.scau.cmi.ema.domain.User;
import cn.edu.scau.cmi.ema.service.base.CmiEmaService;
import cn.edu.scau.cmi.ema.util.CmiSqlUtil;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.Query;
import java.util.*;
@Service("DetectdepartmentService")
@Transactional

public class DetectdepartmentServiceImpl extends CmiEmaService implements DetectdepartmentService {
	public DetectdepartmentServiceImpl() {
	}

	@Transactional
	public Detectdepartment saveDetectdepartment(Detectdepartment detectdepartment) {
		Set<Detect> existingDetectsForDetectdepartment = new HashSet<Detect>();
		Set<User> existingUsersForUser = new HashSet<User>();

		Set<Detect> selectedDetectsForDetectdepartment = detectdepartment.getDetectsForDetectdepartment();
		Set<User> selectedUsersForUser = detectdepartment.getUsersForDetectdepartment();

		if (detectdepartment.getId() == null) {
			Address address = addressDAO.findAddressById(detectdepartment.getAddress().getId());

			Detectdepartment existingDetectdepartment = detectdepartmentDAO
					.findDetectdepartmentByPhysicalPrimaryKey(detectdepartment.getName(), address.getId());

			detectdepartment.setAddress(address);

			if (isEquals(detectdepartment, existingDetectdepartment)) {
				return existingDetectdepartment;
			}

			detectdepartment = detectdepartmentDAO.store(detectdepartment);
			detectdepartmentDAO.flush();

			for (Detect relatedDetect : selectedDetectsForDetectdepartment) {
				relatedDetect.setDetectdepartment(detectdepartment);
				detectDAO.store(relatedDetect);
			}

			for (User relatedUser : selectedUsersForUser) {
				relatedUser.getDetectdepartmentsForUser().add(detectdepartment);
				userDAO.store(relatedUser);
			}
		} else {
			Detectdepartment existingDetectdepartment = detectdepartmentDAO
					.findDetectdepartmentByPrimaryKey(detectdepartment.getId());

			existingDetectsForDetectdepartment = existingDetectdepartment.getDetectsForDetectdepartment();
			existingUsersForUser = existingDetectdepartment.getUsersForDetectdepartment();

			Set<Detect> prepareDeleteDetectsForDetectdepartment = new HashSet<Detect>();
			Set<Detect> prepareAddDetectsForDetectdepartment = new HashSet<Detect>();

			prepareDeleteDetectsForDetectdepartment.addAll(selectedDetectsForDetectdepartment);
			prepareDeleteDetectsForDetectdepartment.addAll(existingDetectsForDetectdepartment);

			prepareAddDetectsForDetectdepartment.addAll(selectedDetectsForDetectdepartment);
			prepareAddDetectsForDetectdepartment.addAll(existingDetectsForDetectdepartment);

			prepareDeleteDetectsForDetectdepartment.removeAll(selectedDetectsForDetectdepartment);
			prepareAddDetectsForDetectdepartment.removeAll(existingDetectsForDetectdepartment);

			for (Detect relatedDetect : prepareAddDetectsForDetectdepartment) {
				relatedDetect.setDetectdepartment(detectdepartment);
				detectDAO.store(relatedDetect);
			}

			for (Detect relatedDetect : prepareDeleteDetectsForDetectdepartment) {
				relatedDetect.setDetectdepartment(null);
				detectDAO.store(relatedDetect);
			}
			Set<User> prepareDeleteUsersForUser = new HashSet<User>();
			Set<User> prepareAddUsersForUser = new HashSet<User>();

			prepareDeleteUsersForUser.addAll(selectedUsersForUser);
			prepareDeleteUsersForUser.addAll(existingUsersForUser);

			prepareAddUsersForUser.addAll(selectedUsersForUser);
			prepareAddUsersForUser.addAll(existingUsersForUser);

			prepareDeleteUsersForUser.removeAll(selectedUsersForUser);
			prepareAddUsersForUser.removeAll(existingUsersForUser);

			for (User relatedUser : prepareAddUsersForUser) {

				relatedUser.getDetectdepartmentsForUser().add(existingDetectdepartment);
				userDAO.store(relatedUser);
			}

			for (User relatedUser : prepareDeleteUsersForUser) {

				relatedUser.getDetectdepartmentsForUser().remove(existingDetectdepartment);
				userDAO.store(relatedUser);
			}
			detectdepartment = detectdepartmentDAO.store(detectdepartment);
			detectdepartmentDAO.flush();
		}

		detectDAO.flush();
		userDAO.flush();
		return detectdepartment;
	}

	public void deleteDetectdepartment(Detectdepartment detectdepartment) {
		detectdepartmentDAO.remove(detectdepartment);
		detectdepartmentDAO.flush();
	}

	@Transactional
	public void deleteDetectdepartments(Set<Integer> deleteDetectdepartmentsId) {
		Query query = detectdepartmentDAO.createNamedQuery("deleteDetectdepartmentsById", -1, -1);
		query.setParameter(1, deleteDetectdepartmentsId);
		query.executeUpdate();
	}

	@Transactional
	public Set<Detectdepartment> loadDetectdepartments() {
		return detectdepartmentDAO.findAllDetectdepartments();

	}

	@Transactional
	public Set<Detectdepartment> loadReferenceDetectdepartments(Set<Detectdepartment> detectdepartments) {
		Iterator<Detectdepartment> detectdepartmentsIterator = detectdepartments.iterator();
		Set<Detectdepartment> referencedDetectdepartments = new HashSet<>();
		while (detectdepartmentsIterator.hasNext()) {
			Detectdepartment currentDetectdepartment = detectdepartmentsIterator.next();

			if (!currentDetectdepartment.getDetectsForDetectdepartment().isEmpty()) {
				referencedDetectdepartments.add(currentDetectdepartment);
				continue;
			}

			if (!currentDetectdepartment.getUsersForDetectdepartment().isEmpty()) {
				referencedDetectdepartments.add(currentDetectdepartment);
				continue;
			}
		}
		return referencedDetectdepartments;
	}

	public Set<Detectdepartment> loadDetectdepartmentsByIdSet(Set<Integer> detectdepartmentIdSet) {

		Iterator<Integer> detectdepartmentIdIterator = detectdepartmentIdSet.iterator();
		Set<Detectdepartment> detectdepartmentSet = new HashSet<>();
		while (detectdepartmentIdIterator.hasNext()) {
			Integer id = detectdepartmentIdIterator.next();
			Detectdepartment currentDetectdepartment = detectdepartmentDAO.findDetectdepartmentById(id);
			detectdepartmentSet.add(currentDetectdepartment);
		}
		return detectdepartmentSet;
	}

	@Transactional
	public List<Detectdepartment> findAllDetectdepartments(Integer startResult, Integer maxRows) {
		return new java.util.ArrayList<Detectdepartment>(
				detectdepartmentDAO.findAllDetectdepartments(startResult, maxRows));
	}

	@Transactional
	public Detectdepartment findDetectdepartmentByPrimaryKey(Integer id) {
		return detectdepartmentDAO.findDetectdepartmentByPrimaryKey(id);
	}

	@Transactional
	public Integer countDetectdepartments() {
		return ((Long) detectdepartmentDAO.createQuerySingleResult("select count(o) from Detectdepartment o")
				.getSingleResult()).intValue();
	}

	@Transactional
	public Integer countDetectdepartments(CmiPagination page) {
		String sql = CmiSqlUtil.createCountHql(page, Detectdepartment.class);
		return ((Long) detectdepartmentDAO.createQuerySingleResult(sql).getSingleResult()).intValue();
	}

	/**
	 * search for name with ajax
	 *
	 */
	@Transactional
	public Integer countDetectdepartmentsByName(String queryName) {
		Query query = detectdepartmentDAO.createNamedQuery("countDetectdepartmentsByName", -1, -1);
		query.setParameter(1, queryName);
		return new Long((long) query.getSingleResult()).intValue();
	}

	@Transactional
	public Integer countDetectdepartmentsByDetachedCriteria(CmiPagination page) {
		DetachedCriteria detachedCriteria = CmiSqlUtil.createDetachedCriteria(page, Detectdepartment.class);
		Session session = (Session) entityManager.getDelegate();
		detachedCriteria.setProjection(Projections.rowCount());
		return new Long((long) detachedCriteria.getExecutableCriteria(session).uniqueResult()).intValue();
	}

	public Map<String, ?> loadDetectdepartmentObjectReferencedSet(Detectdepartment detectdepartment) {
		HashMap<String, Object> objectReferencedSetMap = new HashMap<>();
		if (detectdepartment.getAddress() != null) {

			Set<Integer> addressIds = new HashSet<Integer>();
			addressIds.add(detectdepartment.getAddress().getId());
			objectReferencedSetMap.put("addressIds", addressIds);
		}

		Set<Integer> detectsIds = new HashSet<Integer>();
		for (Detect obj : detectdepartment.getDetectsForDetectdepartment()) {

			detectsIds.add(obj.getId());
		}
		objectReferencedSetMap.put("detectsIds", detectsIds);
		Set<Integer> usersIds = new HashSet<Integer>();
		for (User user : detectdepartment.getUsersForDetectdepartment()) {
			usersIds.add(user.getId());
		}
		objectReferencedSetMap.put("usersIds", usersIds);

		return objectReferencedSetMap;
	}

	public Map<String, ?> loadDetectdepartmentClassReferencedSet(Detectdepartment detectdepartment) {
		HashMap<String, Object> classReferencedSetMap = new HashMap<>();
		classReferencedSetMap.put("addresss", addressDAO.findAllAddresss());
		classReferencedSetMap.put("detects", detectDAO.findAllDetects());
		classReferencedSetMap.put("users", userDAO.findAllUsers());

		return classReferencedSetMap;
	}

	public boolean isEquals(Detectdepartment detectdepartment, Object obj) {
		if (obj == detectdepartment)
			return true;
		if (!(obj instanceof Detectdepartment))
			return false;
		Detectdepartment comparedDetectdepartment = (Detectdepartment) obj;
		if (!CheckPropertyEqual(detectdepartment.getName(), comparedDetectdepartment.getName())) {
			return false;
		}
		if (!CheckPropertyEqual(detectdepartment.getAddress().getId(), comparedDetectdepartment.getAddress().getId())) {
			return false;
		}
		return true;
	}

	public static <T> boolean CheckPropertyEqual(T originProperty, T comparedProperty) {
		// 基本类型经过参数传递后会自动装箱
		String[] className = originProperty.getClass().getName().split("\\.");
		if (className[0].equals("java") && className[1].equals("math")) {
			return ((Comparable) originProperty).compareTo(comparedProperty) == 0 ? true : false;
		} else {
			return originProperty.equals(comparedProperty);
		}
	}
}

